using System;
using System.Data;
using System.Xml;

using OR.Reuse.Persistence;

using Derived = OR.Lazarus.Library.DataTier.Source;

namespace OR.Lazarus.Library.DataTier.Source.Lazarus
{
	/// <summary>
	/// Defines field storage within an Object.
	/// </summary>
   public class FieldDetail : EntityBase
   {
		protected System.String mName;
		protected string mAlias;
		protected System.Boolean mAutoGenerate;
		protected string mDataType;
		protected string mDefaultValue;
		protected string mFriendlyName;
		protected System.Boolean mReadOnly;
		protected System.Boolean mRequired;
		protected object mScale;
		protected object mSize;
		protected System.Boolean mTableOnly;
		protected string mLogicalName;
		protected string mDescription;
	
		protected Derived.ConstraintCollection mConstraints;
		protected Derived.IndexCollection mIndexes;

		public FieldDetail()
		{
			mConstraints = new Derived.ConstraintCollection();
			mConstraints.ParentEntity = this;
			mIndexes = new Derived.IndexCollection();
			mIndexes.ParentEntity = this;
	
		}
	
		/// <summary>
		/// Specifies a unique name for the entity.
		/// </summary>
		public System.String Name
		{
			get
			{
				return ( mName );
			}
			set
			{
				mName = value;
			}
		}

		/// <summary>
		/// The Alias column defines the Field's name when used in an XML context.  It defaults to the lowercase representation of the field Name.
		/// </summary>
		public string Alias
		{
			get
			{
				return ( mAlias );
			}
			set
			{
				mAlias = value;
			}
		}

		/// <summary>
		/// Specifies whether or not the field is system-generated.  Valid DataTypes for AutoGenerate are: * INT, BIGINT: An IDENTITY column is created. * UNIQUEIDENTIFIER: The value is initialized as a new Guid in CREATE procedures. * DATETIME: The value is initialied to the current timestamp in CREATE procedures.
		/// </summary>
		public System.Boolean AutoGenerate
		{
			get
			{
				return ( mAutoGenerate );
			}
			set
			{
				mAutoGenerate = value;
			}
		}

		/// <summary>
		/// Specifies the DataType of the field.  Valid datatypes are: BigInt, Bit, DateTime, Decimal, Float, Identity, Int, Money, SmallInt, Text, Varchar, and Uniqueidentifier.
		/// </summary>
		public string DataType
		{
			get
			{
				return ( mDataType );
			}
			set
			{
				mDataType = value;
			}
		}

		/// <summary>
		/// Specifies the default value of the field in string representation.  The value must be covertable to the Field's DataType.
		/// </summary>
		public string DefaultValue
		{
			get
			{
				return ( mDefaultValue );
			}
			set
			{
				mDefaultValue = value;
			}
		}

		/// <summary>
		/// The Friendly Name of the field is it's real-world name.  Spaces and other punctuation is allowed, if applicable.  For example, the FriendlyName of the [AutoGenerate] field might be "Auto-Generate Values".
		/// </summary>
		public string FriendlyName
		{
			get
			{
				return ( mFriendlyName );
			}
			set
			{
				mFriendlyName = value;
			}
		}

		/// <summary>
		/// Defines whether or not the field can be modified once created.  This is typically reserved for Auto-Generated values.  This defaults to false.
		/// </summary>
		public System.Boolean ReadOnly
		{
			get
			{
				return ( mReadOnly );
			}
			set
			{
				mReadOnly = value;
			}
		}

		/// <summary>
		/// Defines whether the field is required to have a value or not.  This defaults to false.
		/// </summary>
		public System.Boolean Required
		{
			get
			{
				return ( mRequired );
			}
			set
			{
				mRequired = value;
			}
		}

		/// <summary>
		/// Defines the precision of a field's allowed value.  This is typically used with Float datatypes.
		/// </summary>
		public object Scale
		{
			get
			{
				return ( mScale );
			}
			set
			{
				mScale = value;
			}
		}

		/// <summary>
		/// Defines the maximum size of a field's allowed value.  This is typically used with Varchar values.
		/// </summary>
		public object Size
		{
			get
			{
				return ( mSize );
			}
			set
			{
				mSize = value;
			}
		}

		/// <summary>
		/// Specifies whether or not the field's visibility will be restricted to the physical database.  This is typically used for back-end logging, replication-related or autogenerated values.
		/// </summary>
		public System.Boolean TableOnly
		{
			get
			{
				return ( mTableOnly );
			}
			set
			{
				mTableOnly = value;
			}
		}

		/// <summary>
		/// The field's Logical Name is for use in object-oriented and object-based scenarios.  This would be used to identify the field in an ORM, UML or C# object model, for example.  The LogicalName defaults to the Name.
		/// </summary>
		public string LogicalName
		{
			get
			{
				return ( mLogicalName );
			}
			set
			{
				mLogicalName = value;
			}
		}

		/// <summary>
		/// Provides a long-text description for the entity.
		/// </summary>
		public string Description
		{
			get
			{
				return ( mDescription );
			}
			set
			{
				mDescription = value;
			}
		}

		public Derived.ConstraintCollection Constraints
		{
			get
			{
				return ( mConstraints );
			}
			set
			{
				mConstraints = value;
			}
		}

		public Derived.IndexCollection Indexes
		{
			get
			{
				return ( mIndexes );
			}
			set
			{
				mIndexes = value;
			}
		}

		public override void LoadXml( XmlElement pSource )
		{
			// Scalar Values
			mName = DataUtility.GetString( pSource, "name" );
			mAlias = DataUtility.GetString( pSource, "alias" );
			mAutoGenerate = DataUtility.GetBool( pSource, "autogenerate", false );
			mDataType = DataUtility.GetString( pSource, "type" );
			mDefaultValue = DataUtility.GetString( pSource, "default" );
			mFriendlyName = DataUtility.GetString( pSource, "friendly-name" );
			mReadOnly = DataUtility.GetBool( pSource, "readonly", false );
			mRequired = DataUtility.GetBool( pSource, "required", false );
			mScale = DataUtility.GetInt32( pSource, "scale" );
			mSize = DataUtility.GetInt32( pSource, "size" );
			mTableOnly = DataUtility.GetBool( pSource, "tableonly", false );
			mLogicalName = DataUtility.GetString( pSource, "logical-name" );
			XmlElement vDescription = ( XmlElement )pSource.SelectSingleNode( "lz:description", PersistenceConfig.Namespaces );
			
			if ( vDescription != null )
			{
				mDescription = vDescription.InnerText;
			}
			
			XmlElement vConstraints = ( XmlElement )pSource.SelectSingleNode( "lz:constraints", PersistenceConfig.Namespaces );
			
			if ( vConstraints != null )
			{
				mConstraints.LoadXml( vConstraints );
			}
			XmlElement vIndexes = ( XmlElement )pSource.SelectSingleNode( "lz:indexes", PersistenceConfig.Namespaces );
			
			if ( vIndexes != null )
			{
				mIndexes.LoadXml( vIndexes );
			}
		}
		
		public override XmlElement SaveXml( XmlDocument p_docContext )
		{
			XmlElement vNewElement	= p_docContext.CreateElement( "lz", "field", "http://schemas.icitadel.com/Lazarus/Source.xsd" );

			// Scalar Values
			if ( !String.IsNullOrEmpty( mName ) )
			{
				vNewElement.SetAttribute( "name", mName );
			}
					
			if ( !String.IsNullOrEmpty( mAlias ) )
			{
				vNewElement.SetAttribute( "alias", mAlias );
			}
					
			vNewElement.SetAttribute( "autogenerate", mAutoGenerate.ToString() );
			if ( !String.IsNullOrEmpty( mDataType ) )
			{
				vNewElement.SetAttribute( "type", mDataType );
			}
					
			if ( !String.IsNullOrEmpty( mDefaultValue ) )
			{
				vNewElement.SetAttribute( "default", mDefaultValue );
			}
					
			if ( !String.IsNullOrEmpty( mFriendlyName ) )
			{
				vNewElement.SetAttribute( "friendly-name", mFriendlyName );
			}
					
			vNewElement.SetAttribute( "readonly", mReadOnly.ToString() );
			vNewElement.SetAttribute( "required", mRequired.ToString() );
			if ( mScale != null )
			{
				if ( mScale is System.Int32 )
				{
					vNewElement.SetAttribute( "scale", mScale.ToString() );
				}
				else
				{
					throw new ApplicationException( "The value [ " + mScale.ToString() + " ] of type [ " + mScale.GetType().ToString() + " ] is invalid.  The field [ Scale ] must be null or type [ System.Int32 ]." );
				}
			}
			
			if ( mSize != null )
			{
				if ( mSize is System.Int32 )
				{
					vNewElement.SetAttribute( "size", mSize.ToString() );
				}
				else
				{
					throw new ApplicationException( "The value [ " + mSize.ToString() + " ] of type [ " + mSize.GetType().ToString() + " ] is invalid.  The field [ Size ] must be null or type [ System.Int32 ]." );
				}
			}
			
			vNewElement.SetAttribute( "tableonly", mTableOnly.ToString() );
			if ( !String.IsNullOrEmpty( mLogicalName ) )
			{
				vNewElement.SetAttribute( "logical-name", mLogicalName );
			}
					
			if ( !String.IsNullOrEmpty( mDescription ) )
			{
				XmlElement	vDescription = p_docContext.CreateElement( "lz", "description", "http://schemas.icitadel.com/Lazarus/Source.xsd" );
				vDescription.InnerText = mDescription;
				vNewElement.AppendChild( vDescription );
			}
					

			// Collections
			
			XmlElement	vCollection	= null;
			
			vCollection = mConstraints.SaveXml( p_docContext );
			if ( vCollection != null )
			{
				vNewElement.AppendChild( vCollection );
			}
			
			vCollection = mIndexes.SaveXml( p_docContext );
			if ( vCollection != null )
			{
				vNewElement.AppendChild( vCollection );
			}

			return ( vNewElement );
		}

		public virtual object Clone()
		{
			Derived.FieldDetail v_oReturn = new Derived.FieldDetail();
			
			v_oReturn.Name = mName;
			v_oReturn.Alias = mAlias;
			v_oReturn.AutoGenerate = mAutoGenerate;
			v_oReturn.DataType = mDataType;
			v_oReturn.DefaultValue = mDefaultValue;
			v_oReturn.FriendlyName = mFriendlyName;
			v_oReturn.ReadOnly = mReadOnly;
			v_oReturn.Required = mRequired;
			v_oReturn.Scale = mScale;
			v_oReturn.Size = mSize;
			v_oReturn.TableOnly = mTableOnly;
			v_oReturn.LogicalName = mLogicalName;
			v_oReturn.Description = mDescription;
			
			// FK Values

			// Collections

			foreach ( Derived.ConstraintDetail vDetail in mConstraints )
			{
				v_oReturn.Constraints.Add( vDetail.CloneTyped() );
			}

			foreach ( Derived.IndexDetail vDetail in mIndexes )
			{
				v_oReturn.Indexes.Add( vDetail.CloneTyped() );
			}
			
			return ( v_oReturn );
		}

		public virtual Derived.FieldDetail CloneTyped()
		{
			return ( ( Derived.FieldDetail )this.Clone() );
		}
   }
}
   